﻿namespace OutLook.Model.Domains
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.Serialization;
    using OutLook.Model.Infrastructure;

    /// <summary>
    /// Description of loss material
    /// </summary>
    [DataContract]
    public class Loss : IAssignable, IEquatable<Loss>, IValidatable
    {
        #region Constructors

        /// <summary>
        /// Initializes new default instance of loss material 
        /// </summary>
        private Loss() : this(string.Empty, new ChemicalСombination[0]) { }

        /// <summary>
        /// Initializes new instance of loss material 
        /// </summary>
        /// <param name="title">Title of loss material</param>
        /// <param name="composition">Loss material composition</param>
        private Loss(string title, IEnumerable<ChemicalСombination> compositions)
        {
            Title = title;
            Compositions = new List<ChemicalСombination>(compositions);
        }

        #endregion

        #region Properties

        /// <summary>
        /// Title of loss material
        /// </summary>
        [DataMember(Order = 1)]
        public string Title
        {
            get { return m_Title; }
            private set { m_Title = value; }
        }

        /// <summary>
        /// Loss material chemical composition
        /// </summary>
        [DataMember(Order = 2)]
        public List<ChemicalСombination> Compositions
        {
            get { return m_Compositions; }
            private set { m_Compositions = value; }
        }

        #endregion

        #region Factory Method

        /// <summary>
        /// Creates new default instance of loss material 
        /// </summary>
        /// <returns>Default Loss</returns>
        public static Loss Create()
        {
            return new Loss();
        }

        /// <summary>
        /// Creates new instance of loss material 
        /// </summary>
        /// <param name="title">Title of loss material</param>
        /// <param name="compositions">Loss material composition</param>
        /// <returns>New instance of loss material </returns>
        /// <remarks>Can return NULL if input arguments were wrong</remarks>
        public static Loss Create(string title, IEnumerable<ChemicalСombination> compositions)
        {
            if (title == null || compositions == null)
                return null;

            return new Loss(title, compositions);
        }

        #endregion

        #region IAssignable Implementation

        /// <summary>
        /// Assigns values of current loss to the argument object
        /// </summary>
        /// <param name="obj">Object to assign to</param>
        /// <exception cref="ArgumentNullException">If object to assign to is nullable</exception>
        /// <exception cref="NotSupportedException">If object to assign to doesn't fit</exception>
        public void AssignTo(object obj)
        {
            if (obj == null)
                throw new ArgumentNullException();

            if (obj is Loss)
            {
                Loss loss = obj as Loss;
                loss.Title = m_Title;
                loss.Compositions.Clear();
                foreach (ChemicalСombination item in m_Compositions)
                {
                    loss.Compositions.Add(item);
                }

                return;
            }

            throw new NotSupportedException();
        }

        #endregion

        #region IEquatable<Loss> Implementation

        /// <summary>
        /// Compares current Loss with another one
        /// </summary>
        /// <param name="other">Another Loss</param>
        /// <returns>True - If current Loss and another one are equal, otherwise -False</returns>
        public bool Equals(Loss other)
        {
            if (other == null)
                return false;

            if (!Title.Equals(other.Title))
                return false;

            if (Compositions.Count != other.Compositions.Count)
                return false;

            bool result = true;
            for (int i = 0; i < Compositions.Count; i++)
            {
                if (!Compositions[i].Equals(other.Compositions[i]))
                {
                    result = false;
                    break;
                }
            }

            return result;
        }

        #endregion
        #region IValidatable Implementation

        /// <summary>
        /// Validates Loss
        /// </summary>
        /// <returns>True - if current Loss is valid, otherwise - false</returns>
        public bool Validate()
        {
            ///TODO: Loss  VALIDATION
            if (string.IsNullOrWhiteSpace(m_Title) || string.IsNullOrEmpty(m_Title))
                return false;

            if (m_Compositions.Count == 0)
                return false;

            return true;
        }

        #endregion

        #region Fields

        private string m_Title = default(string);
        private List<ChemicalСombination> m_Compositions = default(List<ChemicalСombination>);

        #endregion
    }
}
